#include "device_uart.h"
#include "stm32f1xx_hal.h"

#include "FreeRTOS.h"
#include "semphr.h"

#include <string.h>

#define UART_RX_QUEUE_LEN 100

extern UART_HandleTypeDef huart1;

struct UART_Device g_stm32_uart1;

struct UART_Data
{
    UART_HandleTypeDef *handle;
    SemaphoreHandle_t  xTxSem;
	QueueHandle_t xRxQueue;
	uint8_t rxdata;
};


void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart)
{
    struct UART_Data *data;
    
    if(huart == &huart1)    
    {
        data = g_stm32_uart1.priv_data;
        
        /* Release semaphore. */
        xSemaphoreGiveFromISR(data->xTxSem, NULL);
    }
    
}


void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	struct UART_Data *uart_data;

	if(huart == &huart1)
	{
		uart_data = g_stm32_uart1.priv_data;
		
		/* Write queue. */
		xQueueSendFromISR(uart_data->xRxQueue, &uart_data->rxdata, NULL);

		HAL_UART_Receive_IT(uart_data->handle, &uart_data->rxdata, 1);
	}
}

static int stm32_uart_init(struct UART_Device * pDev, int baud, int datas, char parity, int stop)
{
    struct UART_Data *uart_data = pDev->priv_data;
    
    uart_data->xTxSem = xSemaphoreCreateBinary();
	uart_data->xRxQueue = xQueueCreate(UART_RX_QUEUE_LEN, 1);

	HAL_UART_Receive_IT(uart_data->handle, &uart_data->rxdata, 1);
	
    return 0;
}

static int stm32_uart_send(struct UART_Device * pDev, uint8_t *datas, int len, int timeout_ms)
{
    struct UART_Data *uart_data = pDev->priv_data;
    
    /* Just to trigger an interrupt */
    HAL_UART_Transmit_IT(uart_data->handle, datas, len);
    
    /* Wait until the transmission is complete. */
    if(pdTRUE == xSemaphoreTake(uart_data->xTxSem, timeout_ms))
    {
        return 0;
    }
    else
    {
        return -1;
    }
}

static int stm32_uart_recv(struct UART_Device * pDev, uint8_t *data, int timeout_ms)
{
	struct UART_Data *uart_data = pDev->priv_data;

    if(pdPASS == xQueueReceive(uart_data->xRxQueue, data, timeout_ms))
    {
		return 0;
	}
	else
	{
		return -1;
	}
	
    /* Read data from the queue. */
	HAL_UART_Receive_IT();
	
    return 0;
}

static struct UART_Data g_stm32_uart1_data =
{
    &huart1,
	
};

static struct UART_Device g_stm32_uart1 = 
{
    "stm32_uart1",
    stm32_uart_init,
    stm32_uart_send,
    stm32_uart_recv,
    &g_stm32_uart1_data,
};

struct UART_Device *g_uart_devs[] = {&g_stm32_uart1};

struct UART_Device *GetUARTDevice(char *name)
{
	int i = 0;

	for(i=0; i<sizeof(g_uart_devs)/sizeof(g_uart_devs[0]); i++)
	{
		if(0 == strcmp(name, g_uart_devs[i])->name)
		{
			return g_uart_devs[i];
		}
	}
	
	return NULL;
		
}


